package dhy.com.service;

import dhy.com.clawer.ClawerProperties;
import dhy.com.doamin.ClawerBean;
import dhy.com.doamin.QuartzBean;
import dhy.com.exception.CustomException;
import dhy.com.exception.CustomExceptionType;
import dhy.com.quarz.QuartzUtils;
import dhy.com.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.scheduling.support.CronSequenceGenerator;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;



//爬虫服务
@Service
@Slf4j
public class ClawerService {
    @Resource
    private Scheduler scheduler;
    @Resource
    private ClawerProperties clawerProperties;
    //默认每隔10秒执行一次爬虫
    private final String DEFAULT_CRON = "0/10 * * * * ?";
    //默认起始页
    private final Integer DEFAULT_PAGENUM = 1;
    //jobname的统一后缀
    private final String JOBNAME_SUFFIX = "-Job";

    //开始爬取
    public void start() {
        //TODO:目前只设置一个用户只能开启一个爬虫线程
        List<JobDetail> userClawerList = getUserClawerList();
        //当前用户开启了一个爬虫线程，还未关闭，不能继续开启爬虫线程
        if (userClawerList != null && userClawerList.size() == 1) {
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR, "请先关闭已经开启的爬虫线程");
        }

        ClawerBean clawerBean = wiredClawerBean();
        QuartzBean pictureClawerJob = QuartzBean.builder().jobClass("dhy.com.quarz.PictureClawerJob")
                .jobName(clawerBean.getSessionID() + JOBNAME_SUFFIX)
                //五分钟执行一次
                .cronExpression(DEFAULT_CRON).build();
        //判断用户输入的cron表达式的合法性
        if (clawerBean.getCron() != null) {
            boolean validExpression = CronSequenceGenerator.isValidExpression(clawerBean.getCron());
            log.info("当前用户输入的cron表达式为:{}", clawerBean.getCron());
            if (!validExpression)
                throw new CustomException(CustomExceptionType.USER_INPUT_ERROR, "您输入的cron表达式有误");
            //用户输入的cron表达式有效
            pictureClawerJob.setCronExpression(clawerBean.getCron());
        }
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("clawerBean", clawerBean);
        jobDataMap.put("filename", clawerProperties.getFilePathPrefix() + clawerBean.getSessionID() + "/");
        try {
            //创建并执行指定任务
            QuartzUtils.createScheduleJobWithParams(scheduler, pictureClawerJob, jobDataMap);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    //获取request和session
    public ClawerBean wiredClawerBean() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession session = requestAttributes.getRequest().getSession(false);

        if(session==null)
        {
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR,"请先开启爬虫线程");
        }

        return ClawerBean.builder().
                keyWord((String) session.getAttribute("keyWord"))
                .pageNum(session.getAttribute("pageNum") == null ? DEFAULT_PAGENUM : Integer.parseInt((String) session.getAttribute("pageNum")))
                .endPageNum(session.getAttribute("endPageNum") != null ?
                        Integer.parseInt((String) session.getAttribute("endPageNum"))
                        : null)
                .sessionID(session.getId())
                .cron((String) session.getAttribute("cron"))
                .build();
    }

    //获取当前用户开启的爬虫线程
    public List<JobDetail> getUserClawerList() {
        //TODO:目前只设置一个用户只能开启一个爬虫线程
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession session = requestAttributes.getRequest().getSession(false);
        if(session==null)
        {
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR,"请先开启爬虫线程");
        }
        return QuartzUtils.getUserClawerList(scheduler, session.getId() + JOBNAME_SUFFIX);
    }

    //停止爬取
    public void stopClawer(HttpSession session) {
        try {
            //TODO:删除不存在的任务不会报错
            QuartzUtils.deleteScheduleJob(scheduler, session.getId() + JOBNAME_SUFFIX);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    //获取正在运行的所有job--显示的是正在工作的爬虫任务，当任务进入休息间隔的时候，不会显示
    public List<String> getAliveList() {
        return QuartzUtils.getAliveClawerList(scheduler);
    }

    //获取所有job
    public List<String> getClawerList() {
        return QuartzUtils.getClawerList(scheduler);
    }

    //下载爬取到的图片
    public synchronized void downLoad()  {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession session = requestAttributes.getRequest().getSession();
        //用户是否开启了爬虫线程----主要判断session,如果为空，抛出异常
         if(session==null)
             throw new CustomException(CustomExceptionType.USER_INPUT_ERROR,"请先爬取再下载资源");
        String sessionID =session.getId();
        //判断当前用户的爬虫线程是否关闭
        List<JobDetail> userClawerList = getUserClawerList();
        //当前用户开启了一个爬虫线程，还未关闭，不能继续开启爬虫线程
        if (userClawerList != null && userClawerList.size() == 1) {
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR, "请先关闭已经开启的爬虫线程");
        }

        //TODO:将下载的图片,的文件夹进行打包
        String zipPath="";
        try {
            zipPath = FileUtils.toZip(clawerProperties.getFilePathPrefix() + sessionID + "/");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


        HttpServletResponse response = requestAttributes.getResponse();
        File file = new File(zipPath);
        if (file == null||!file.exists())
            throw new CustomException(CustomExceptionType.SYSTEM_ERROR, "下载的文件不存在");
        response.setContentType("application/octet-stream");
        response.setHeader("content-type", "application/octet-stream");
        try {
            response.addHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode(file.getName(), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        byte[] buffer = new byte[1024];
        OutputStream os=null;
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis))
        {
             os = response.getOutputStream();
            int i = -1;
            while ((i = bis.read(buffer)) != -1) {
                os.write(buffer, 0, i);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //删除文件压缩包
            FileUtils.delFile(zipPath);
        }
    }

    //判断当前用户是否开启了爬虫线程
    public boolean isStartClawer()
    {
        //判断当前用户是否开启了爬虫线程
        //当前用户开启了一个爬虫线程，还未关闭，不能继续开启爬虫线程
        if (getUserClawerList() == null || getUserClawerList().size() == 0) {
           return false;
        }
        return true;
    }

    //清理工作
    public  synchronized void  exit()
    {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession session = requestAttributes.getRequest().getSession();
        FileUtils.delFile(clawerProperties.getFilePathPrefix() + session.getId() + "/");
    }
}
